home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 22 / Cream of the Crop 22.iso / math / ast53src.zip / XCHARTS1.C < prev    next >
C/C++ Source or Header  |  1996-09-29  |  42KB  |  1,151 lines

  1. /*
  2. ** Astrolog (Version 5.30) File: xcharts1.c
  3. **
  4. ** IMPORTANT NOTICE: The graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1996 by Walter D. Pullen
  6. ** (Astara@msn.com, http://www.magitech.com/~cruiser1/astrolog.htm).
  7. ** Permission is granted to freely use and distribute these routines
  8. ** provided one doesn't sell, restrict, or profit from them in any way.
  9. ** Modification is allowed provided these notices remain with any
  10. ** altered or edited versions of the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 9/22/1996.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40.  
  41. #ifdef GRAPH
  42. /*
  43. ******************************************************************************
  44. ** Single Chart Graphics Routines.
  45. ******************************************************************************
  46. */
  47.  
  48. /* Draw a wheel chart, in which the 12 signs and houses are delineated, and  */
  49. /* the planets are inserted in their proper places. This is the default      */
  50. /* graphics chart to generate, as is done when the -v or -w (or no) switches */
  51. /* are included with -X. Draw the aspects in the middle of chart, too.       */
  52.  
  53. void XChartWheel()
  54. {
  55.   real xsign[cSign+1], xhouse[cSign+1], xplanet[objMax], symbol[objMax];
  56.   int cx, cy, i, j;
  57.   real asc, unitx, unity;
  58.  
  59.   /* Set up variables and temporarily automatically decrease the horizontal */
  60.   /* chart size to leave room for the sidebar if that mode is in effect.    */
  61.  
  62.   if (gs.fText && !us.fVelocity)
  63.     gs.xWin -= xSideT;
  64.   cx = gs.xWin/2 - 1; cy = gs.yWin/2 - 1;
  65.   unitx = (real)cx; unity = (real)cy;
  66.   asc = gs.objLeft ? planet[abs(gs.objLeft)]+90*(gs.objLeft < 0) : chouse[1];
  67.  
  68.   /* Fill out arrays with the angular degree on the circle of where to    */
  69.   /* place each object, cusp, and sign glyph based on how the chart mode. */
  70.  
  71.   if (gi.nMode == gWheel) {
  72.     for (i = 1; i <= cSign; i++)
  73.       xhouse[i] = PZ(chouse[i]);
  74.   } else {
  75.     asc -= chouse[1];
  76.     for (i = 1; i <= cSign; i++)
  77.       xhouse[i] = PZ(ZFromS(i));
  78.   }
  79.   for (i = 1; i <= cSign; i++)
  80.     xsign[i] = PZ(HousePlaceInX(ZFromS(i)));
  81.   for (i = 0; i <= cObj; i++)
  82.     xplanet[i] = PZ(HousePlaceInX(planet[i]));
  83.  
  84.   /* Go draw the outer sign and house rings. */
  85.  
  86.   DrawWheel(xsign, xhouse, cx, cy, unitx, unity, asc,
  87.     0.65, 0.70, 0.75, 0.80, 0.875);
  88.  
  89.   for (i = 0; i <= cObj; i++)    /* Figure out where to put planet glyphs. */
  90.     symbol[i] = xplanet[i];
  91.   FillSymbolRing(symbol, 1.0);
  92.  
  93.   /* For each planet, draw a small dot indicating where it is, and then */
  94.   /* a line from that point to the planet's glyph.                      */
  95.  
  96.   DrawSymbolRing(symbol, xplanet, ret, cx, cy, unitx, unity,
  97.     0.50, 0.52, 0.56, 0.60);
  98.  
  99.   /* Draw lines connecting planets which have aspects between them. */
  100.  
  101.   if (!gs.fAlt) {                /* Don't draw aspects in bonus mode. */
  102.     if (!FCreateGrid(fFalse))
  103.       return;
  104.     for (j = cObj; j >= 1; j--)
  105.       for (i = j-1; i >= 0; i--)
  106.         if (grid->n[i][j] && FProper(i) && FProper(j)) {
  107.           DrawColor(kAspB[grid->n[i][j]]);
  108.           DrawDash(cx+POINT1(unitx, 0.48, PX(xplanet[i])),
  109.             cy+POINT1(unity, 0.48, PY(xplanet[i])),
  110.             cx+POINT1(unitx, 0.48, PX(xplanet[j])),
  111.             cy+POINT1(unity, 0.48, PY(xplanet[j])),
  112.             abs(grid->v[i][j]/60/2));
  113.         }
  114.   }
  115.  
  116.   /* Go draw sidebar with chart information and positions if need be. */
  117.  
  118.   DrawInfo();
  119. }
  120.  
  121.  
  122. /* Draw an astro-graph chart on a map of the world, i.e. the draw the     */
  123. /* Ascendant, Descendant, Midheaven, and Nadir lines corresponding to the */
  124. /* time in the chart. This chart is done when the -L switch is combined   */
  125. /* with the -X switch.                                                    */
  126.  
  127. void XChartAstroGraph()
  128. {
  129.   real planet1[objMax], planet2[objMax],
  130.     end1[cObj*2+1], end2[cObj*2+1],
  131.     symbol1[cObj*2+1], symbol2[cObj*2+1],
  132.     lon = Lon, longm, x, y, z, ad, oa, am, od, dm, lat;
  133.   int unit = gi.nScale, fStroke, lat1 = -60, lat2 = 75, y1, y2, xold1, xold2,
  134.     i, j, k, l;
  135.  
  136.   /* Erase top and bottom parts of map. We don't draw the astro-graph lines */
  137.   /* above certain latitudes, and this gives us room for glyph labels, too. */
  138.  
  139.   y1 = (91-lat1)*gi.nScale;
  140.   y2 = (91-lat2)*gi.nScale;
  141.   DrawColor(gi.kiOff);
  142.   DrawBlock(0, 1, gs.xWin-1, y2-1);
  143.   DrawBlock(0, y1+1, gs.xWin-1, gs.yWin-2);
  144.   DrawColor(gi.kiLite);
  145.   DrawDash(0, gs.yWin/2, gs.xWin-2, gs.yWin/2, 4);    /* Draw equator. */
  146.   DrawColor(gi.kiOn);
  147.   DrawLine(1, y2, gs.xWin-2, y2);
  148.   DrawLine(1, y1, gs.xWin-2, y1);
  149.   for (i = 1; i <= cObj*2; i++)
  150.     end1[i] = end2[i] = -rLarge;
  151.  
  152.   /* Draw small hatches every 5 degrees along edges of world map. */
  153.  
  154.   DrawColor(gi.kiLite);
  155.   for (i = lat1; i <= lat2; i += 5) {
  156.     j = (91-i)*gi.nScale;
  157.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  158.     DrawLine(1, j, k, j);
  159.     DrawLine(gs.xWin-2, j, gs.xWin-1-k, j);
  160.   }
  161.   for (i = -180; i < 180; i += 5) {
  162.     j = (180-i)*gi.nScale;
  163.     k = (2+(i%10 == 0)+2*(i%30 == 0)+(i%90 == 0))*gi.nScaleT;
  164.     DrawLine(j, y2+1, j, y2+k);
  165.     DrawLine(j, y1-1, j, y1-k);
  166.   }
  167.   if (us.fLatitudeCross) {
  168.     DrawColor(kRainbowB[7]);
  169.     i = (int)((91.0-Lat)*(real)gi.nScale);
  170.     DrawLine(0, i, gs.xWin-1, i);
  171.   }
  172.  
  173. #ifdef MATRIX
  174.   /* Calculate zenith locations of each planet. */
  175.  
  176.   for (i = 1; i <= cObj; i++) if (!ignore[i] || i == oMC) {
  177.     planet1[i] = RFromD(Tropical(i == oMC ? is.MC : planet[i]));
  178.     planet2[i] = RFromD(planetalt[i]);
  179.     EclToEqu(&planet1[i], &planet2[i]);
  180.   }
  181.  
  182.   /* Draw the Midheaven lines and zenith location markings. */
  183.  
  184.   if (lon < 0.0)
  185.     lon += rDegMax;
  186.   for (i = 1; i <= cObj; i++) if (FProper(i)) {
  187.     x = planet1[oMC]-planet1[i];
  188.     if (x < 0.0)
  189.       x += 2.0*rPi;
  190.     if (x > rPi)
  191.       x -= 2.0*rPi;
  192.     z = lon+DFromR(x);
  193.     if (z > rDegHalf)
  194.       z -= rDegMax;
  195.     j = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  196.     DrawColor(kElemB[eEar]);
  197.     DrawLine(j, y1+unit*4, j, y2-unit*1);
  198.     end2[i*2-1] = (real)j;
  199.     y = DFromR(planet2[i]);
  200.     k = (int)((91.0-y)*(real)gi.nScale);
  201.     if (FBetween((int)y, lat1, lat2)) {
  202.       DrawColor(gi.kiLite);
  203.       DrawBlock(j-gi.nScaleT, k-gi.nScaleT, j+gi.nScaleT, k+gi.nScaleT);
  204.       DrawColor(gi.kiOff);
  205.       DrawBlock(j, k, j, k);
  206.     }
  207.  
  208.     /* Draw Nadir lines assuming we aren't in bonus chart mode. */
  209.  
  210.     if (!gs.fAlt) {
  211.       j += 180*gi.nScale;
  212.       if (j > gs.xWin-2)
  213.         j -= (gs.xWin-2);
  214.       end1[i*2-1] = (real)j;
  215.       DrawColor(kElemB[eWat]);
  216.       DrawLine(j, y1+unit*2, j, y2-unit*2);
  217.     }
  218.   }
  219.  
  220.   /* Now, normally, unless we are in bonus chart mode, we will go on to draw */
  221.   /* the Ascendant and Descendant lines here.                                */
  222.  
  223.   longm = RFromD(Mod(DFromR(planet1[oMC])+lon));
  224.   if (!gs.fAlt) for (i = 1; i <= cObj; i++) if (FProper(i)) {
  225.     xold1 = xold2 = -1000;
  226.  
  227.     /* Hack: Normally we draw the Ascendant and Descendant line segments  */
  228.     /* simultaneously. However, for the PostScript and metafile stroke    */
  229.     /* graphics, this will case the file to get inordinately large due to */
  230.     /* the constant thrashing between the Asc and Desc colors. Hence for  */
  231.     /* these charts only, we'll do two passes for Asc and Desc.           */
  232.     fStroke = gs.fPS || gs.fMeta;
  233.     for (l = 0; l <= fStroke; l++)
  234.  
  235.     for (lat = (real)lat1; lat <= (real)lat2;
  236.       lat += 1.0/(real)(gi.nScale/gi.nScaleT)) {
  237.  
  238.       /* First compute and draw the current segment of Ascendant line. */
  239.  
  240.       j = (int)((91.0-lat)*(real)gi.nScale);
  241.       ad = RTan(planet2[i])*RTan(RFromD(lat));
  242.       if (ad*ad > 1.0)
  243.         ad = rLarge;
  244.       else {
  245.         ad = RAsin(ad);
  246.         oa = planet1[i]-ad;
  247.         if (oa < 0.0)
  248.           oa += 2.0*rPi;
  249.         am = oa-rPiHalf;
  250.         if (am < 0.0)
  251.           am += 2.0*rPi;
  252.         z = longm-am;
  253.         if (z < 0.0)
  254.           z += 2.0*rPi;
  255.         if (z > rPi)
  256.           z -= 2.0*rPi;
  257.         z = DFromR(z);
  258.         k = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  259.         if (!fStroke || !l) {
  260.           DrawColor(kElemB[eFir]);
  261.           DrawWrap(xold1, j+gi.nScaleT, k, j, 1, gs.xWin-2);
  262.           if (lat == (real)lat1) {                          /* Line segment */
  263.             DrawLine(k, y1, k, y1+unit*4);                  /* pointing to  */
  264.             end2[i*2] = (real)k;                            /* Ascendant.   */
  265.           }
  266.         } else if (lat == (real)lat1)
  267.           end2[i*2] = (real)k;
  268.         xold1 = k;
  269.       }
  270.  
  271.       /* The curving Ascendant and Descendant lines actually touch at low or */
  272.       /* high latitudes. Sometimes when we start out, a particular planet's  */
  273.       /* lines haven't appeared yet, i.e. we are scanning at a latitude      */
  274.       /* where our planet's lines don't exist. If this is the case, then     */
  275.       /* when they finally do start, draw a thin horizontal line connecting  */
  276.       /* the Ascendant and Descendant lines so they don't just start in      */
  277.       /* space. Note that these connected lines aren't labeled with glyphs.  */
  278.  
  279.       if (ad == rLarge) {
  280.         if (xold1 >= 0) {
  281.           if (!fStroke || !l) {
  282.             DrawColor(gi.kiGray);
  283.             DrawWrap(xold1, j+1, xold2, j+1, 1, gs.xWin-2);
  284.           }
  285.           lat = rDegQuad;
  286.         }
  287.       } else {
  288.  
  289.       /* Then compute and draw corresponding segment of Descendant line. */
  290.  
  291.         od = planet1[i]+ad;
  292.         dm = od+rPiHalf;
  293.         z = longm-dm;
  294.         if (z < 0.0)
  295.           z += 2.0*rPi;
  296.         if (z > rPi)
  297.           z -= 2.0*rPi;
  298.         z = DFromR(z);
  299.         k = (int)(Mod(rDegHalf-z+gs.nRot)*(real)gi.nScale);
  300.         if (xold2 < 0 && lat > (real)lat1 && (!fStroke || l)) {
  301.           DrawColor(gi.kiGray);
  302.           DrawWrap(xold1, j, k, j, 1, gs.xWin-2);
  303.         }
  304.         if (!fStroke || l) {
  305.           DrawColor(kElemB[eAir]);
  306.           DrawWrap(xold2, j+gi.nScaleT, k, j, 1, gs.xWin-2);
  307.           if (lat == (real)lat1)                            /* Line segment */
  308.             DrawLine(k, y1, k, y1+unit*2);                  /* pointing to  */
  309.         }                                                   /* Descendant.  */
  310.         xold2 = k;
  311.       }
  312.     }
  313. #endif /* MATRIX */
  314.  
  315.     /* Draw segments pointing to top of Ascendant and Descendant lines. */
  316.  
  317.     if (ad != rLarge) {
  318.       DrawColor(kElemB[eFir]);
  319.       DrawLine(xold1, y2, xold1, y2-unit*1);
  320.       DrawColor(kElemB[eAir]);
  321.       DrawLine(k, y2, k, y2-unit*2);
  322.       end1[i*2] = (real)k;
  323.     }
  324.   }
  325.  
  326.   DrawColor(kMainB[8]);
  327.   i = (int)((181.0-Lon)*(real)gi.nScale);
  328.   j = (int)((91.0-Lat)*(real)gi.nScale);
  329.   if (us.fLatitudeCross)
  330.     DrawSpot(i, j);
  331.   else
  332.     DrawPoint(i, j);
  333.  
  334.   /* Determine where to draw the planet glyphs. We have four sets of each    */
  335.   /* planet - each planet's glyph appearing in the chart up to four times -  */
  336.   /* one for each type of line. The Midheaven and Ascendant lines are always */
  337.   /* labeled at the bottom of the chart, while the Nadir and Midheaven lines */
  338.   /* at the top. Therefore we need to place two sets of glyphs, twice.       */
  339.  
  340.   for (i = 1; i <= cObj*2; i++) {
  341.     symbol1[i] = end1[i];
  342.     symbol2[i] = end2[i];
  343.   }
  344.   FillSymbolLine(symbol1);
  345.   FillSymbolLine(symbol2);
  346.  
  347.   /* Now actually draw the planet glyphs. */
  348.  
  349.   for (i = 1; i <= cObj*2; i++) {
  350.     j = (i+1)/2;
  351.     if (FProper(j)) {
  352.       if ((gi.xTurtle = (int)symbol1[i]) > 0 && gs.fLabel) {
  353.         DrawColor(ret[j] < 0.0 ? gi.kiGray : gi.kiOn);
  354.         DrawDash((int)end1[i], y2-unit*2, (int)symbol1[i], y2-unit*4,
  355.           (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  356.         DrawObject(j, gi.xTurtle, y2-unit*10);
  357.       }
  358.       if ((gi.xTurtle = (int)symbol2[i]) > 0) {
  359.         DrawColor(ret[j] < 0.0 ? gi.kiGray : gi.kiOn);
  360.         DrawDash((int)end2[i], y1+unit*4, (int)symbol2[i], y1+unit*8,
  361.           (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  362.         DrawObject(j, gi.xTurtle, y1+unit*14);
  363.         DrawTurtle(szDrawObject[i & 1 ? oMC : oAsc], (int)symbol2[i],
  364.           y1+unit*24-gi.nScaleT);
  365.       }
  366.     }
  367.   }
  368. }
  369.  
  370.  
  371. /* Draw an aspect and midpoint grid in the window, with planets labeled down */
  372. /* the diagonal. This chart is done when the -g switch is combined with the  */
  373. /* -X switch. The chart always has a certain number of cells; hence based    */
  374. /* how the restrictions are set up, there may be blank columns and rows,     */
  375. /* or else only the first number of unrestricted objects will be included.   */
  376.  
  377. void XChartGrid()
  378. {
  379.   char sz[cchSzDef];
  380.   int unit, siz, x, y, i, j, k;
  381.   KI c;
  382.  
  383.   unit = CELLSIZE*gi.nScale; siz = gs.nGridCell*unit;
  384.   if (!FCreateGrid(gs.fAlt))
  385.     return;
  386.  
  387.   /* Loop through each cell in each row and column of grid. */
  388.  
  389.   for (y = 1, j = oEar-1; y <= gs.nGridCell; y++) {
  390.     do {
  391.       j++;
  392.     } while (!FProper(j) && j <= cObj);
  393.     DrawColor(gi.kiGray);
  394.     DrawDash(0, y*unit, siz, y*unit, !gs.fColor);
  395.     DrawDash(y*unit, 0, y*unit, siz, !gs.fColor);
  396.     if (j <= cObj) for (x = 1, i = oEar-1; x <= gs.nGridCell; x++) {
  397.       do {
  398.         i++;
  399.       } while (!FProper(i) && i <= cObj);
  400.       if (i <= cObj) {
  401.         gi.xTurtle = x*unit-unit/2;
  402.         gi.yTurtle = y*unit-unit/2 -
  403.           (gi.nScale/gi.nScaleT > 2 ? 5*gi.nScaleT : 0);
  404.         k = grid->n[i][j];
  405.  
  406.         /* If this is an aspect cell, draw glyph of aspect in effect. */
  407.  
  408.         if (gs.fAlt ? x > y : x < y) {
  409.           if (k) {
  410.             DrawColor(c = kAspB[k]);
  411.             DrawAspect(k, gi.xTurtle, gi.yTurtle);
  412.           }
  413.  
  414.         /* If this is a midpoint cell, draw glyph of sign of midpoint. */
  415.  
  416.         } else if (gs.fAlt ? x < y : x > y) {
  417.           DrawColor(c = kSignB(grid->n[i][j]));
  418.           DrawSign(grid->n[i][j], gi.xTurtle, gi.yTurtle);
  419.  
  420.         /* For cells on main diagonal, draw glyph of planet. */
  421.  
  422.         } else {
  423.           DrawColor(gi.kiLite);
  424.           DrawEdge((y-1)*unit, (y-1)*unit, y*unit, y*unit);
  425.           DrawObject(i, gi.xTurtle, gi.yTurtle);
  426.         }
  427.  
  428.         /* When the scale size is 300+, we can print text in each cell: */
  429.  
  430.         if (gi.nScale/gi.nScaleT > 2 && gs.fLabel) {
  431.           k = abs(grid->v[i][j]);
  432.  
  433.           /* For the aspect portion, print the orb in degrees and minutes. */
  434.  
  435.           if (gs.fAlt ? x > y : x < y) {
  436.             if (grid->n[i][j])
  437.               sprintf(sz, "%c%d %02d'", k != grid->v[i][j] ? (us.fAppSep ?
  438.                 'a' : '-') : (us.fAppSep ? 's' : '+'), k/60, k%60);
  439.             else
  440.               sprintf(sz, "");
  441.  
  442.           /* For the midpoint portion, print the degrees and minutes. */
  443.  
  444.           } else if (gs.fAlt ? x < y : x > y)
  445.             sprintf(sz, "%2d %02d'", k/60, k%60);
  446.  
  447.           /* For the main diagonal, print degree and sign of each planet. */
  448.  
  449.           else {
  450.             c = kSignB(grid->n[i][j]);
  451.             sprintf(sz, "%c%c%c %02d", chSig3(grid->n[i][j]), k);
  452.           }
  453.           DrawColor(c);
  454.           DrawSz(sz, x*unit-unit/2, y*unit-3*gi.nScaleT, dtBottom);
  455.         }
  456.       }
  457.     }
  458.   }
  459. }
  460.  
  461.  
  462. /* Draw the local horizon, and draw in the planets where they are at the */
  463. /* time in question, as done when the -Z is combined with the -X switch. */
  464.  
  465. void XChartHorizon()
  466. {
  467.   real lat, lonz[objMax], latz[objMax], azi[objMax], alt[objMax];
  468.   int x[objMax], y[objMax], m[objMax], n[objMax],
  469.     cx, cy, unit, x1, y1, x2, y2, xs, ys, i, j, k, l;
  470.   char sz[2];
  471.  
  472.   unit = Max(12, 6*gi.nScale);
  473.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  474.   unit = 12*gi.nScale;
  475.   xs = x2-x1; ys = y2-y1; cx = (x1+x2)/2; cy = (y1+y2)/2;
  476.  
  477.   /* Make a slightly smaller rectangle within the window to draw the planets */
  478.   /* in. Make segments on all four edges marking 5 degree increments.        */
  479.  
  480.   DrawColor(gi.kiLite);
  481.   for (i = 5; i < 180; i += 5) {
  482.     j = y1+(int)((real)i*(real)ys/rDegHalf);
  483.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  484.     DrawLine(x1+1, j, x1+1+k, j);
  485.     DrawLine(x2-1, j, x2-1-k, j);
  486.   }
  487.   sz[1] = chNull;
  488.   for (i = 5; i < nDegMax; i += 5) {
  489.     j = x1+(int)((real)i*(real)xs/rDegMax);
  490.     k = (2+(i%10 == 0)+2*(i%30 == 0))*gi.nScaleT;
  491.     DrawLine(j, y1+1, j, y1+1+k);
  492.     DrawLine(j, y2-1, j, y2-1-k);
  493.     if (i % 90 == 0) {
  494.       *sz = *szDir[i/90 & 3];
  495.       DrawSz(sz, j, y1-2*gi.nScaleT, dtBottom);
  496.     }
  497.   }
  498.  
  499.   /* Draw vertical lines dividing our rectangle into four areas. In our     */
  500.   /* local space chart, the middle line represents due south, the left line */
  501.   /* due east, the right line due west, and the edges due north. A fourth   */
  502.   /* horizontal line divides that which is above and below the horizon.     */
  503.  
  504.   DrawColor(gi.kiGray);
  505.   DrawDash(cx, y1, cx, y2, 1);
  506.   DrawDash((cx+x1)/2, y1, (cx+x1)/2, y2, 1);
  507.   DrawDash((cx+x2)/2, y1, (cx+x2)/2, y2, 1);
  508.   DrawColor(gi.kiOn);
  509.   DrawEdge(x1, y1, x2, y2);
  510.   DrawDash(x1, cy, x2, cy, 1);
  511.  
  512.   /* Calculate the local horizon coordinates of each planet. First convert */
  513.   /* zodiac position and declination to zenith longitude and latitude.     */
  514.  
  515.   lat = RFromD(Lat);
  516.   for (i = 0; i <= cObj; i++) if (!ignore[i] || i == oMC) {
  517.     lonz[i] = RFromD(Tropical(planet[i])); latz[i] = RFromD(planetalt[i]);
  518.     EclToEqu(&lonz[i], &latz[i]);
  519.   }
  520.   for (i = 0; i <= cObj; i++) if (FProper(i)) {
  521.     lonz[i] = RFromD(Mod(DFromR(lonz[oMC]-lonz[i]+rPiHalf)));
  522.     EquToLocal(&lonz[i], &latz[i], rPiHalf-lat);
  523.     azi[i] = rDegMax-DFromR(lonz[i]); alt[i] = DFromR(latz[i]);
  524.     x[i] = x1+(int)((real)xs*(Mod(rDegQuad-azi[i]))/rDegMax+rRound);
  525.     y[i] = y1+(int)((real)ys*(rDegQuad-alt[i])/rDegHalf+rRound);
  526.     m[i] = x[i]; n[i] = y[i]+unit/2;
  527.   }
  528.  
  529.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  530.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  531.   /* drawn on top of each other if possible. Again, we assume that we'll */
  532.   /* put the glyph right under the point, unless there would be some     */
  533.   /* overlap and the above position is better off.                       */
  534.  
  535.   for (i = 0; i <= cObj; i++) if (FProper(i)) {
  536.     k = l = gs.xWin+gs.yWin;
  537.     for (j = 1; j < i; j++) if (FProper(j)) {
  538.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  539.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  540.     }
  541.     if (k < unit || l < unit)
  542.       if (k < l)
  543.         n[i] -= unit;
  544.   }
  545.   for (i = cObj; i >= 0; i--) if (FProper(i))    /* Draw planet's glyph. */
  546.     DrawObject(i, m[i], n[i]);
  547.   for (i = cObj; i >= 0; i--) if (FProper(i)) {
  548.     DrawColor(kObjB[i]);
  549.     if (!gs.fAlt || i > oNorm)
  550.       DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  551.     else                          /* near glyph indicating   */
  552.       DrawSpot(x[i], y[i]);       /* exact local location.   */
  553.   }
  554. }
  555.  
  556.  
  557. /* Draw the local horizon, and draw in the planets where they are at the  */
  558. /* time in question. This chart is done when the -Z0 is combined with the */
  559. /* -X switch. This is an identical function to XChartHorizon(); however,  */
  560. /* that routine's chart is entered on the horizon and meridian. Here we   */
  561. /* center the chart around the center of the sky straight up from the     */
  562. /* local horizon, with the horizon itself being an encompassing circle.   */
  563.  
  564. void XChartHorizonSky()
  565. {
  566.   real lat, rx, ry, s, sqr2,
  567.     lonz[objMax], latz[objMax], azi[objMax], alt[objMax];
  568.   int x[objMax], y[objMax], m[objMax], n[objMax],
  569.     cx, cy, unit, x1, y1, x2, y2, xs, ys, i, j, k, l;
  570.  
  571.   unit = Max(12, 6*gi.nScale);
  572.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  573.   unit = 12*gi.nScale;
  574.   xs = x2-x1; ys = y2-y1; cx = (x1+x2)/2; cy = (y1+y2)/2;
  575.  
  576.   /* Draw a circle in window to indicate horizon line, lines dividing   */
  577.   /* the window into quadrants to indicate n/s and w/e meridians, and   */
  578.   /* segments on these lines and the edges marking 5 degree increments. */
  579.  
  580.   sqr2 = RSqr(2.0);
  581.   DrawColor(gi.kiGray);
  582.   DrawDash(cx, y1, cx, y2, 1);
  583.   DrawDash(x1, cy, x2, cy, 1);
  584.   DrawColor(gi.kiLite);
  585.   for (i = -125; i <= 125; i += 5) {
  586.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  587.     s = 1.0/(rDegQuad*sqr2);
  588.     j = cy+(int)(s*ys/2*i);
  589.     DrawLine(cx-k, j, cx+k, j);
  590.     j = cx+(int)(s*xs/2*i);
  591.     DrawLine(j, cy-k, j, cy+k);
  592.   }
  593.   for (i = 5; i < 55; i += 5) {
  594.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  595.     s = 1.0/(rDegHalf-rDegQuad*sqr2);
  596.     j = (int)(s*ys/2*i);
  597.     DrawLine(x1, y1+j, x1+k, y1+j);
  598.     DrawLine(x1, y2-j, x1+k, y2-j);
  599.     DrawLine(x2, y1+j, x2-k, y1+j);
  600.     DrawLine(x2, y2-j, x2-k, y2-j);
  601.     j = (int)(s*xs/2*i);
  602.     DrawLine(x1+j, y1, x1+j, y1+k);
  603.     DrawLine(x2-j, y1, x2-j, y1+k);
  604.     DrawLine(x1+j, y2, x1+j, y2-k);
  605.     DrawLine(x2-j, y2, x2-j, y2-k);
  606.   }
  607.   DrawSz("N", cx, y1-2*gi.nScaleT, dtBottom);
  608.   DrawSz("E", x1/2, cy+2*gi.nScaleT, dtCent);
  609.   DrawSz("W", (gs.xWin+x2)/2, cy+2*gi.nScaleT, dtCent);
  610.   if (!gs.fText)
  611.     DrawSz("S", cx, gs.yWin-3*gi.nScaleT, dtBottom);
  612.   rx = xs/2/sqr2; ry = ys/2/sqr2;
  613.   DrawColor(gi.kiOn);
  614.   DrawEdge(x1, y1, x2, y2);
  615.   DrawCircle(cx, cy, (int)rx, (int)ry);
  616.   for (i = 0; i < nDegMax; i += 5) {
  617.     k = (2+(i/10*10 == i ? 1 : 0)+(i/30*30 == i ? 2 : 0))*gi.nScaleT;
  618.     DrawLine(cx+(int)((rx-k)*RCosD((real)i)), cy+(int)((ry-k)*RSinD((real)i)),
  619.       cx+(int)((rx+k)*RCosD((real)i)), cy+(int)((ry+k)*RSinD((real)i)));
  620.   }
  621.  
  622.   /* Calculate the local horizon coordinates of each planet. First convert */
  623.   /* zodiac position and declination to zenith longitude and latitude.     */
  624.  
  625.   lat = RFromD(Lat);
  626.   for (i = 0; i <= cObj; i++) if (!ignore[i] || i == oMC) {
  627.     lonz[i] = RFromD(Tropical(planet[i])); latz[i] = RFromD(planetalt[i]);
  628.     EclToEqu(&lonz[i], &latz[i]);
  629.   }
  630.   for (i = 0; i <= cObj; i++) if (FProper(i)) {
  631.     lonz[i] = RFromD(Mod(DFromR(lonz[oMC]-lonz[i]+rPiHalf)));
  632.     EquToLocal(&lonz[i], &latz[i], rPiHalf-lat);
  633.     azi[i] = rDegMax-DFromR(lonz[i]); alt[i] = rDegQuad-DFromR(latz[i]);
  634.     s = alt[i]/rDegQuad;
  635.     x[i] = cx+(int)(rx*s*RCosD(rDegHalf+azi[i])+rRound);
  636.     y[i] = cy+(int)(ry*s*RSinD(rDegHalf+azi[i])+rRound);
  637.     if (!FOnWin(x[i], y[i]))
  638.       x[i] = -1000;
  639.     m[i] = x[i]; n[i] = y[i]+unit/2;
  640.   }
  641.  
  642.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  643.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  644.   /* drawn on top of each other if possible. Again, we assume that we'll */
  645.   /* put the glyph right under the point, unless there would be some     */
  646.   /* overlap and the above position is better off.                       */
  647.  
  648.   for (i = 0; i <= cObj; i++) if (FProper(i)) {
  649.     k = l = gs.xWin+gs.yWin;
  650.     for (j = 0; j < i; j++) if (FProper(j)) {
  651.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  652.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  653.     }
  654.     if (k < unit || l < unit)
  655.       if (k < l)
  656.         n[i] -= unit;
  657.   }
  658.   for (i = cObj; i >= 0; i--) if (m[i] >= x1 && FProper(i))  /* Draw glyph. */
  659.     DrawObject(i, m[i], n[i]);
  660.   for (i = cObj; i >= 0; i--) if (x[i] >= y1 && FProper(i)) {
  661.     DrawColor(kObjB[i]);
  662.     if (!gs.fAlt || i > oNorm)
  663.       DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  664.     else                          /* near glyph indicating   */
  665.       DrawSpot(x[i], y[i]);       /* exact local location.   */
  666.   }
  667. }
  668.  
  669.  
  670. /* Draw a chart depicting an aerial view of the solar system in space, with */
  671. /* all the planets drawn around the Sun, and the specified central planet   */
  672. /* in the middle, as done when the -S is combined with the -X switch.       */
  673.  
  674. void XChartOrbit()
  675. {
  676.   int x[objMax], y[objMax], m[objMax], n[objMax],
  677.     cx = gs.xWin / 2, cy = gs.yWin / 2, unit, x1, y1, x2, y2, i, j, k, l;
  678.   real sx, sy, sz = 30.0, xp, yp, a;
  679.  
  680.   unit = Max(gs.fText*12, 6*gi.nScale);
  681.   x1 = unit; y1 = unit; x2 = gs.xWin-1-unit; y2 = gs.yWin-1-unit;
  682.   unit = 12*gi.nScale;
  683.  
  684.   /* Determine the scale of the chart. For a scale size of 400+, make the */
  685.   /* graphic 1 AU in radius (just out to Earth's orbit). For 300, make    */
  686.   /* the chart 6 AU in radius (enough for inner planets out to asteroid   */
  687.   /* belt). For a scale of 200, make window 30 AU in radius (enough for   */
  688.   /* planets out to Neptune). For scale of 100, make it 90 AU in radius   */
  689.   /* (enough for all planets including the orbits of the uranians.)       */
  690.  
  691.   if (gi.nScale/gi.nScaleT < 2)
  692.     sz = 90.0;
  693.   else if (gi.nScale/gi.nScaleT == 3)
  694.     sz = 6.0;
  695.   else if (gi.nScale/gi.nScaleT > 3)
  696.     sz = 1.0;
  697.   sx = (real)(cx-x1)/sz; sy = (real)(cy-y1)/sz;
  698.   for (i = 0; i <= oNorm; i++) if (FProper(i)) {
  699.     xp = spacex[i]; yp = spacey[i];
  700.     x[i] = cx-(int)(xp*sx); y[i] = cy+(int)(yp*sy);
  701.     m[i] = x[i]; n[i] = y[i]+unit/2;
  702.   }
  703.  
  704.   /* As in the DrawGlobe() routine, we now determine where to draw the   */
  705.   /* glyphs in relation to the actual points, so that the glyphs aren't  */
  706.   /* drawn on top of each other if possible. Again, we assume that we'll */
  707.   /* put the glyph right under the point, unless there would be some     */
  708.   /* overlap and the above position is better off.                       */
  709.  
  710.   for (i = 0; i <= oNorm; i++) if (FProper(i)) {
  711.     k = l = gs.xWin+gs.yWin;
  712.     for (j = 0; j < i; j++) if (FProper(j)) {
  713.       k = Min(k, abs(m[i]-m[j])+abs(n[i]-n[j]));
  714.       l = Min(l, abs(m[i]-m[j])+abs(n[i]-unit-n[j]));
  715.     }
  716.     if (k < unit || l < unit)
  717.       if (k < l)
  718.         n[i] -= unit;
  719.   }
  720.  
  721.   /* Draw the 12 sign boundaries from the center body to edges of screen. */
  722.  
  723.   a = Mod(DFromR(Angle(spacex[oJup], spacey[oJup]))-planet[oJup]);
  724.   DrawColor(gi.kiGray);
  725.   for (i = 0; i < cSign; i++) {
  726.     k = cx+2*(int)((real)cx*RCosD((real)i*30.0+a));
  727.     l = cy+2*(int)((real)cy*RSinD((real)i*30.0+a));
  728.     DrawClip(cx, cy, k, l, x1, y1, x2, y2, 1);
  729.   }
  730.   DrawColor(gi.kiLite);
  731.   DrawEdge(x1, y1, x2, y2);
  732.   for (i = oNorm; i >= 0; i--)
  733.     if (FProper(i) && FInRect(m[i], n[i], x1, y1, x2, y2))
  734.       DrawObject(i, m[i], n[i]);
  735.   for (i = oNorm; i >= 0; i--)
  736.     if (FProper(i) && FInRect(x[i], y[i], x1, y1, x2, y2)) {
  737.       DrawColor(kObjB[i]);
  738.       if (!gs.fAlt || i > oNorm)
  739.         DrawPoint(x[i], y[i]);      /* Draw small or large dot */
  740.       else                          /* near glyph indicating   */
  741.         DrawSpot(x[i], y[i]);       /* exact orbital location. */
  742.     }
  743. }
  744.  
  745.  
  746. /* Draw a chart showing the 36 Gauquelin sectors, with all the planets    */
  747. /* positioned in their appropriate sector (and at the correct fracton     */
  748. /* across the sector) as done when the -l is combined with the -X switch. */
  749.  
  750. void XChartSector()
  751. {
  752.   real xplanet[objMax], symbol[objMax];
  753.   char sz[3];
  754.   int cx, cy, i, j, k;
  755.   real unitx, unity, px, py, temp;
  756.  
  757.   if (gs.fText && !us.fVelocity)
  758.     gs.xWin -= xSideT;
  759.   cx = gs.xWin/2 - 1; cy = gs.yWin/2 - 1;
  760.   unitx = (real)cx; unity = (real)cy;
  761.  
  762.   /* Draw lines across the whole chart at the four angles. */
  763.  
  764.   DrawColor(gi.kiLite);
  765.   DrawDash(cx+POINT1(unitx, 0.99, PX(0.0)),
  766.            cy+POINT1(unity, 0.99, PY(0.0)),
  767.            cx+POINT1(unitx, 0.99, PX(180.0)),
  768.            cy+POINT1(unity, 0.99, PY(180.0)), !gs.fColor);
  769.   DrawDash(cx+POINT1(unitx, 0.99, PX(90.0)),
  770.            cy+POINT1(unity, 0.99, PY(90.0)),
  771.            cx+POINT1(unitx, 0.99, PX(270.0)),
  772.            cy+POINT1(unity, 0.99, PY(270.0)), !gs.fColor);
  773.  
  774.   /* Draw circles and radial lines delineating the 36 sectors. */
  775.  
  776.   DrawColor(gi.kiOn);
  777.   for (i = 0; i < nDegMax; i += 10) {
  778.     px = PX((real)i); py = PY((real)i);
  779.     DrawLine(cx+POINT1(unitx, 0.81, px), cy+POINT1(unity, 0.81, py),
  780.       cx+POINT2(unitx, 0.95, px), cy+POINT2(unity, 0.95, py));
  781.   }
  782.   DrawCircle(cx, cy, (int)(unitx*0.95+rRound), (int)(unity*0.95+rRound));
  783.   DrawCircle(cx, cy, (int)(unitx*0.81+rRound), (int)(unity*0.81+rRound));
  784.  
  785.   /* Label the 36 sectors, with plus zones in red and normal in dark green. */
  786.  
  787.   k = pluszone[cSector];
  788.   for (i = 1; i <= cSector; i++) {
  789.     j = pluszone[i];
  790.     DrawColor(j ? kRainbowB[1] : kMainB[5]);
  791.     sprintf(sz, "%d", i);
  792.     DrawSz(sz, cx+POINT1(unitx, 0.88, PX((real)(i*10+175)))+
  793.       (FBetween(i, 12, 19) ? -(gi.nScale/* *gi.nScaleT*/) : 0),
  794.       cy+POINT1(unity, 0.88, PY((real)(i*10+175)))+(gi.nScale/* *gi.nScaleT*/),
  795.       dtCent | dtScale);
  796.     sprintf(sz, "%c", j ? '+' : '-');
  797.     DrawSz(sz, cx+POINT1(unitx, 0.97, PX((real)(i*10+175))),
  798.       cy+POINT1(unity, 0.97, PY((real)(i*10+175)))+gi.nScaleT*2, dtCent);
  799.     if (j != k) {
  800.       DrawColor(gi.kiGray);
  801.       DrawDash(cx, cy, cx+POINT2(unitx, 0.81, PX((real)(i*10+170))),
  802.         cy+POINT2(unity, 0.81, PY((real)(i*10+170))), 1);
  803.     }
  804.     k = j;
  805.   }
  806.  
  807.   CastSectors();    /* Go compute the planets' sector positions. */
  808.  
  809.   for (i = 0; i <= cObj; i++)    /* Figure out where to put planet glyphs. */
  810.     symbol[i] = xplanet[i] = Mod(rDegHalf - planet[i]);
  811.   FillSymbolRing(symbol, 1.0);
  812.  
  813.   /* For each planet, draw a small dot indicating where it is, and then */
  814.   /* a line from that point to the planet's glyph.                      */
  815.  
  816.   for (i = cObj; i >= 0; i--) if (FProper(i)) {
  817.     if (gs.fLabel) {
  818.       temp = symbol[i];
  819.       DrawColor(ret[i] < 0.0 ? gi.kiGray : gi.kiOn);
  820.       DrawDash(cx+POINT1(unitx, 0.67, PX(xplanet[i])),
  821.         cy+POINT1(unity, 0.67, PY(xplanet[i])),
  822.         cx+POINT1(unitx, 0.71, PX(temp)),
  823.         cy+POINT1(unity, 0.71, PY(temp)),
  824.         (ret[i] < 0.0 ? 1 : 0) - gs.fColor);
  825.       DrawObject(i, cx+POINT1(unitx, 0.75, PX(temp)),
  826.         cy+POINT1(unity, 0.75, PY(temp)));
  827.     } else
  828.       DrawColor(kObjB[i]);
  829.     DrawPoint(cx+POINT1(unitx, 0.65, PX(xplanet[i])),
  830.       cy+POINT1(unity, 0.65, PY(xplanet[i])));
  831.   }
  832.  
  833.   /* Draw lines connecting planets which have aspects between them. */
  834.  
  835.   CastChart(fTrue);
  836.   if (!gs.fAlt) {                /* Don't draw aspects in bonus mode. */
  837.     if (!FCreateGrid(fFalse))
  838.       return;
  839.     for (j = cObj; j >= 1; j--)
  840.       for (i = j-1; i >= 0; i--)
  841.         if (grid->n[i][j] && FProper(i) && FProper(j)) {
  842.           DrawColor(kAspB[grid->n[i][j]]);
  843.           DrawDash(cx+POINT1(unitx, 0.63, PX(xplanet[i])),
  844.             cy+POINT1(unity, 0.63, PY(xplanet[i])),
  845.             cx+POINT1(unitx, 0.63, PX(xplanet[j])),
  846.             cy+POINT1(unity, 0.63, PY(xplanet[j])),
  847.             abs(grid->v[i][j]/60/2));
  848.         }
  849.   }
  850.  
  851.   DrawInfo();
  852. }
  853.  
  854.  
  855. /* Draw an arrow from one point to another, a line with an arrowhead at the */
  856. /* ending point. The size of the arrowhead is based on current scale size,  */
  857. /* and the line segment is actually shorter and doesn't touch either        */
  858. /* endpoint by the same amount. This is used by XChartDispositor() below.   */
  859.  
  860. void DrawArrow(x1, y1, x2, y2)
  861. int x1, y1, x2, y2;
  862. {
  863.   real r, s, a;
  864.  
  865.   r = DFromR(Angle((real)(x2-x1), (real)(y2-y1)));
  866.   s = (real)(gi.nScale*8);
  867.   x1 += (int)(s*RCosD(r)); y1 += (int)(s*RSinD(r));    /* Shrink line by    */
  868.   x2 -= (int)(s*RCosD(r)); y2 -= (int)(s*RSinD(r));    /* the scale amount. */
  869.   s = (real)(gi.nScale)*4.5;
  870.   DrawLine(x1, y1, x2, y2);                            /* Main segment. */
  871.   for (a = -1.0; a <= 1.0; a += 2.0)
  872.     DrawLine(x2, y2, x2 + (int)(s*RCosD(r + a*135.0)), /* The two arrow     */
  873.       y2 + (int)(s*RSinD(r + a*135.0)));               /* head line pieces. */
  874. }
  875.  
  876.  
  877. /* Draw dispositor graphs for the 10 main planets, as done when the -j is   */
  878. /* combined with the -X switch. Four graphs are drawn, one in each screen   */
  879. /* quadrant. A dispositor graph may be based on the sign or house position, */
  880. /* and the planets may be arranged in a hierarchy or a wheel format.        */
  881.  
  882. void XChartDispositor()
  883. {
  884.   int oDis[oMain+1], dLev[oMain+1], cLev[oMain+1], xo[oMain+1], yo[oMain+1];
  885.   real xCirc[oMain+1], yCirc[oMain+1];
  886.   char sz[cchSzDef];
  887.   int xLev, yLev, xSub, ySub, cx0, cy0, cx, cy, i, j, k;
  888.  
  889.   /* Set up screen positions of the 10 planets for the wheel graphs. */
  890.  
  891.   cx0 = gs.xWin / 2; cy0 = gs.yWin / 2;
  892.   for (i = 1; i <= oMain; i++) {
  893.     if ((j = (180-(i-1)*360/oMain)) < 0)
  894.       j += nDegMax;
  895.     xCirc[i] = (real)cx0*0.4*RCosD((real)j);
  896.     yCirc[i] = (real)cy0*0.4*RSinD((real)j);
  897.   }
  898.  
  899.   /* Loop over the two basic dispositor types: sign based and house based. */
  900.  
  901.   for (xSub = 0; xSub <= 1; xSub++) {
  902.     cx = xSub * cx0 + cx0 / 2;
  903.  
  904.     /* For each planet, get its dispositor planet for current graph type. */
  905.  
  906.     for (i = 1; i <= oMain; i++) {
  907.       oDis[i] = rules[xSub ? inhouse[i] : SFromZ(planet[i])];
  908.       dLev[i] = 1;
  909.     }
  910.  
  911.     /* Determine the final dispositors (including mutual reception loops). */
  912.  
  913.     do {
  914.       j = fFalse;
  915.       for (i = 1; i <= oMain; i++)
  916.         cLev[i] = fFalse;
  917.       for (i = 1; i <= oMain; i++)
  918.         if (dLev[i])
  919.           cLev[oDis[i]] = fTrue;
  920.       for (i = 1; i <= oMain; i++)    /* A planet isn't a final dispositor */
  921.         if (dLev[i] && !cLev[i]) {    /* if nobody is pointing to it.      */
  922.           dLev[i] = 0;
  923.           j = fTrue;
  924.         }
  925.     } while (j);
  926.  
  927.     /* Determine the level of each planet, i.e. how many times you have to */
  928.     /* jump to your dispositor before reaching a final, with finals == 1.  */
  929.  
  930.     do {
  931.       j = fFalse;
  932.       for (i = 1; i <= oMain; i++)
  933.         if (!dLev[i]) {
  934.           if (!dLev[oDis[i]])
  935.             j = fTrue;
  936.           else                              /* If my dispositor already has */
  937.             dLev[i] = dLev[oDis[i]] + 1;    /* a level, mine is one more.   */
  938.         }
  939.     } while (j);
  940.  
  941.     /* Count the number of planets at each dispositor level. */
  942.  
  943.     for (i = 1; i <= oMain; i++)
  944.       cLev[i] = 0;
  945.     for (i = 1; i <= oMain; i++)
  946.       cLev[dLev[i]]++;
  947.  
  948.     /* Count the number of levels total, and max planets on any one level. */
  949.  
  950.     xLev = yLev = 0;
  951.     for (i = 1; i <= oMain; i++)
  952.       if (cLev[i]) {
  953.         yLev = i;
  954.         if (cLev[i] > xLev)
  955.           xLev = cLev[i];
  956.       }
  957.  
  958.     /* Loop over our two dispositor display formats: hierarchy and wheel. */
  959.  
  960.     for (ySub = 0; ySub <= 1; ySub++) {
  961.       cy = ySub * cy0 + cy0 / 2;
  962.       sprintf(sz, "%s dispositor %s.", xSub ? "House" : "Sign",
  963.         ySub ? "wheel" : "hierarchy");
  964.       DrawColor(gi.kiLite);
  965.       DrawSz(sz, cx, ySub * cy0 + 3*gi.nScaleT, dtTop);
  966.  
  967.       if (ySub) {
  968.  
  969.         /* Draw a graph in wheel format. */
  970.  
  971.         for (i = 1; i <= oMain; i++) {
  972.           DrawObject(i, cx + (int)xCirc[i], cy + (int)yCirc[i]);
  973.           j = oDis[i];
  974.           if (j != i) {
  975.             if (dLev[i] < 2)
  976.               DrawColor(gi.kiOn);
  977.             else
  978.               DrawColor(kObjB[i]);
  979.             DrawArrow(cx + (int)xCirc[i], cy + (int)yCirc[i],
  980.               cx + (int)xCirc[j], cy + (int)yCirc[j]);
  981.           }
  982.           if (!gs.fAlt && (j == i || dLev[i] < 2)) {
  983.             DrawColor(j == i ? gi.kiOn : gi.kiGray);
  984.             DrawCircle(cx + (int)xCirc[i], cy + (int)yCirc[i],
  985.               7*gi.nScale, 7*gi.nScale);
  986.           }
  987.         }
  988.       } else {
  989.  
  990.         /* For level hierarchies, first figure out the screen coordinates    */
  991.         /* for each planet, based on its level, total levels, and max width. */
  992.  
  993.         for (i = 1; i <= oMain; i++) {
  994.           yo[i] = cy0*(dLev[i]*2-1)/(yLev*2);
  995.           k = 0;
  996.           for (j = 1; j < i; j++)
  997.             if (dLev[i] == dLev[j])
  998.               k = j;
  999.           if (k)
  1000.             xo[i] = xo[k] + cx0/xLev;    /* One right of last one on level. */
  1001.           else
  1002.             xo[i] = cx - ((cx0/xLev)*(cLev[dLev[i]]-1)/2);
  1003.         }
  1004.  
  1005.         /* Draw graph in level hierarchy format. */
  1006.  
  1007.         for (i = 1; i <= oMain; i++) {
  1008.           DrawObject(i, xo[i], yo[i]);
  1009.           j = oDis[i];
  1010.           if (j != i) {
  1011.             if (dLev[i] < 2) {
  1012.               if (abs(xo[i] - xo[j]) < cx0/xLev*3/2) {
  1013.                 DrawColor(gi.kiOn);
  1014.                 DrawArrow(xo[i], yo[i], xo[j], yo[j]);
  1015.               }
  1016.               DrawColor(gi.kiGray);
  1017.             } else {
  1018.               DrawColor(kObjB[i]);
  1019.               DrawArrow(xo[i], yo[i], xo[j], yo[j]);
  1020.             }
  1021.           } else
  1022.             DrawColor(gi.kiOn);
  1023.           if (!gs.fAlt && dLev[i] < 2)
  1024.             DrawCircle(xo[i], yo[i], 7*gi.nScale, 7*gi.nScale);
  1025.         }
  1026.       }
  1027.     }
  1028.   }
  1029.  
  1030.   /* Draw boundary lines between the four separate dispositor graphs. */
  1031.  
  1032.   if (gs.fBorder) {
  1033.     DrawColor(gi.kiLite);
  1034.     DrawBlock(cx0, 0, cx0, gs.yWin);
  1035.     DrawBlock(0, cy0, gs.xWin, cy0);
  1036.   }
  1037. }
  1038.  
  1039.  
  1040. /* Draw a graphical calendar for a given month, with numbers in boxes,  */
  1041. /* scaled to fit within the given bounds. This is used for single month */
  1042. /* -K switch images and is called 12 times for a full year -Ky image.   */
  1043.  
  1044. void DrawCalendar(mon, X1, Y1, X2, Y2)
  1045. int mon, X1, Y1, X2, Y2;
  1046. {
  1047.   char sz[cchSzDef];
  1048.   int day, cday, dayHi, cweek, xunit, yunit, xs, ys, x1, y1, x, y, s;
  1049.  
  1050.   xs = X2 - X1; ys = Y2 - Y1;
  1051.   day = DayOfWeek(mon, 1, Yea);    /* Day of week of 1st of month.     */
  1052.   cday = DaysInMonth(mon, Yea);    /* Count of days in the month.      */
  1053.   dayHi = DayInMonth(mon, Yea);    /* Number of last day in the month. */
  1054.   cweek = us.fCalendarYear ? 6 : (day + cday + 6) / 7;   /* Week rows. */
  1055.   xunit = xs/8;                    /* Hor. pixel size of each day box. */
  1056.   yunit = ys/(cweek+2);            /* Ver. pixel size of each day box. */
  1057.   x1 = X1 + (xs - xunit*7) / 2;    /* Blank space to left of calendar. */
  1058.   y1 = Y1 + yunit*3/2;             /* Blank space to top of calendar.  */
  1059.  
  1060.   /* Print the month and year in big letters at top of chart. */
  1061.  
  1062.   DrawColor(gi.kiOn);
  1063.   sprintf(sz, "%s, %d", szMonth[mon], Yea);
  1064.   s = gi.nScale;
  1065.   gi.nScale = Min((yunit*3/2-yFont*s) / yFont, xs/9/*CchSz(sz)*/ / xFont);
  1066.   gi.nScale = Max(gi.nScale-1, 1);
  1067.   DrawSz(sz, X1 + xs/2, Y1 + (yunit*3/2-yFont*s)/2, dtCent | dtScale);
  1068.   gi.nScale = s;
  1069.  
  1070.   /* Draw the grid of boxes for the days. */
  1071.  
  1072.   for (x = 0; x <= cWeek; x++) {
  1073.  
  1074.     /* Print days of week at top of each column (abbreviated if need be). */
  1075.  
  1076.     if (x < cWeek) {
  1077.       if (xunit / (xFont*gi.nScale) < 9)
  1078.         sprintf(sz, "%c%c%c", chDay3(x));
  1079.       else
  1080.         sprintf(sz, "%s", szDay[x]);
  1081.       DrawColor(kRainbowB[3]);
  1082.       DrawSz(sz, x1 + x*xunit + xunit/2, y1 - s*3, dtBottom | dtScale);
  1083.       DrawColor(kRainbowB[5]);
  1084.     }
  1085.     DrawLine(x1 + x*xunit, y1, x1 + x*xunit, y1 + cweek*yunit);
  1086.   }
  1087.   for (y = 0; y <= cweek; y++)
  1088.     DrawLine(x1, y1 + y*yunit, x1 + 7*xunit, y1 + y*yunit);
  1089.  
  1090.   /* Actually draw the day numbers in their appropriate boxes. */
  1091.  
  1092.   x = day; y = 0;
  1093.   for (day = 1; day <= dayHi; day = AddDay(mon, day, Yea, 1)) {
  1094.     sprintf(sz, gs.fText ? "%2d" : "%d", day);
  1095.     DrawColor(day == Day && mon == Mon && gs.fLabel ? kRainbowB[4] :
  1096.       (x <= 0 || x >= cWeek-1 ? kRainbowB[1] : gi.kiLite));
  1097.     if (!gs.fAlt)
  1098.       DrawSz(sz, x1 + x*xunit + s*2, y1 + y*yunit + s*4,
  1099.         dtLeft | dtTop | dtScale);
  1100.     else
  1101.       DrawSz(sz, x1 + x*xunit + xunit/2,
  1102.         y1 + y*yunit + yunit/2 + gi.nScale, dtCent | dtScale);
  1103.     if (++x >= cWeek) {
  1104.       x = 0;
  1105.       y++;
  1106.     }
  1107.   }
  1108. }
  1109.  
  1110.  
  1111. /* Draw a graphical calendar on the screen for the chart month or entire */
  1112. /* year, as done when the -K or -Ky is combined with the -X switch.      */
  1113.  
  1114. void XChartCalendar()
  1115. {
  1116.   int xs, ys, xunit, yunit, x1, y1, x, y;
  1117.  
  1118.   if (!us.fCalendarYear) {
  1119.     DrawCalendar(Mon, 0, 0, gs.xWin, gs.yWin);
  1120.     return;
  1121.   }
  1122.  
  1123.   /* Determine the best sized rectangle of months to draw the year in based */
  1124.   /* on the chart dimensions: Either do 6x2 months, or 4x3, 3x4, or 2x6.    */
  1125.  
  1126.   if (gs.xWin > gs.yWin) {
  1127.     if (gs.xWin > gs.yWin * 3) {
  1128.       xs = 6; ys = 2;
  1129.     } else {
  1130.       xs = 4; ys = 3;
  1131.     }
  1132.   } else {
  1133.     if (gs.yWin > gs.xWin * 2) {
  1134.       xs = 2; ys = 6;
  1135.     } else {
  1136.       xs = 3; ys = 4;
  1137.     }
  1138.   }
  1139.   xunit = gs.xWin / xs; yunit = gs.yWin / ys;
  1140.   x1 = (gs.xWin - xunit*xs) / 2;
  1141.   y1 = (gs.yWin - yunit*ys) / 2;
  1142.   for (y = 0; y < ys; y++)
  1143.     for (x = 0; x < xs; x++) {
  1144.       DrawCalendar(y * xs + x + 1, x1 + x*xunit, y1 + y*yunit,
  1145.         x1 + (x+1)*xunit, y1 + (y+1)*yunit);
  1146.     }
  1147. }
  1148. #endif /* GRAPH */
  1149.  
  1150. /* xcharts1.c */
  1151.